package com.yz.bi.service.impl;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yz.bi.manager.BdManager;
import com.yz.model.dto.chart.ChartAddRequest;
import com.yz.model.dto.chart.ChartQueryRequest;
import com.yz.model.dto.chart.ChartUpdateRequest;
import com.yz.model.dto.chart.GenChartByAiRequest;
import com.yz.model.vo.bi.ChartVo;
import com.yz.bi.constant.CommonConstant;
import com.yz.bi.manager.AiManager;
import com.yz.bi.mapper.ChartMapper;
import com.yz.bi.mq.BiMessageProducer;
import com.yz.model.entity.bi.Chart;
import com.yz.bi.service.BiService;
import com.yz.common.limiting.RedisLimiter;
import com.yz.common.utils.ExcelUtils;
import com.yz.common.utils.SqlUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created With IntelliJ IDEA.
 * Descriptions:
 * <p>
 * User:Mr.Du
 * Date:2024/4/10
 * Time:19:36
 */
@Slf4j
@Service
public class BiServiceImpl extends ServiceImpl<ChartMapper, Chart> implements BiService {

    @Resource
    private RedisLimiter redisLimiter;

    @Resource
    private AiManager aiManager;

    @Resource
    private BiMessageProducer biMessageProducer;

    @Resource
    private BdManager bdManager;

    @Resource
    private PlatformTransactionManager transactionManager;


    @Override
    public Long addChart(Long uid, ChartAddRequest chartAddRequest) {
        Chart chart = Chart.builder().build();
        BeanUtils.copyProperties(chartAddRequest, chart);
        chart.setUid(uid);
        boolean save = this.save(chart);
        if(!save){
            log.error("保存失败");
            throw new RuntimeException("保存失败");
        }
        return chart.getId();
    }

    /**
     * 通过AI生成图表
     *
     * @param uid 用户ID
     * @param multipartFile 用户上传的文件
     * @param genChartByAiRequest 包含图表生成请求的参数
     * @return ChartVo 包含生成的图表信息的响应对象
     */
//    @Override
//    @Transactional
//    public ChartVo genChartByAi(Long uid, MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest) {
//        try{
//            // 通过Redis限流，防止同一用户频繁调用
//            redisLimiter.doRateLimit("genChartByAi_" + uid);
//
//            // 校验请求参数
//            String name = genChartByAiRequest.getName();
//            String goal = genChartByAiRequest.getGoal();
//            String chartType = genChartByAiRequest.getChartType();
//            if(name == null || goal == null || chartType == null){
//                throw new RuntimeException("参数不能为空");
//            }
//
//            // 检查文件大小
//            long size = multipartFile.getSize();
//            if(size > 1024 * 1024L){
//                throw new RuntimeException("文件大小不能超过1M");
//            }
//
//            // 校验文件类型
//            final List<String> validFileSuffixList = Arrays.asList("xlsx", "xls");
//            String fileName = multipartFile.getOriginalFilename();
//            String suffix = FileUtil.getSuffix(fileName);
//            if(!validFileSuffixList.contains(suffix)){
//                throw new RuntimeException("文件类型不支持");
//            }
//
//            // 处理用户目标信息
//            String userGoal = null;
//            if(StringUtils.isNotBlank(chartType)){
//                userGoal = goal + "，请使用" + chartType;
//            }
//
//            // 组装用户需求和原始数据信息
//            StringBuilder sb = new StringBuilder();
//            sb.append("分析需求：").append(userGoal).append("\n");
//            String data = ExcelUtils.excelToCSV(multipartFile, suffix);
//            sb.append("原始数据：").append(data).append("\n");
//            log.info("promote信息: {}", sb.toString());
//            // 调用AI服务进行分析
//            String res = aiManager.doChat(CommonConstant.BI_MODE_ID, sb.toString());
//            log.info("AI 生成结果：{}", res);
//            String[] result = res.split("【【【【【");
//            if(result.length < 2){
//                throw new RuntimeException("AI 生成错误");
//            }
//
//            // 解析AI返回的结果，并保存到数据库
//            String genChart = result[1];
//            String genResult = result[2];
//            Chart chart = Chart.builder()
//                    .name(name)
//                    .goal(goal)
//                    .chartData(data)
//                    .chartType(chartType)
//                    .genChart(genChart)
//                    .genResult(genResult)
//                    .uid(uid)
//                    .status("succeed")
//                    .build();
//            boolean save = this.save(chart);
//            if(!save){
//                log.info("保存表单失败");
//                throw new RuntimeException("保存表单失败");
//            }
//
//            // 构建并返回响应对象
//            ChartVo chartVo = new ChartVo();
//            BeanUtils.copyProperties(chart, chartVo);
//            return chartVo;
//        }catch (Exception e){
//            log.error("AI生成图表失败", e);
//            throw new RuntimeException("AI生成图表失败");
//        }
//
//    }

    /**
     * 通过AI生成图表,使用baidu
     *
     * @param uid 用户ID
     * @param multipartFile 用户上传的文件
     * @param genChartByAiRequest 包含图表生成请求的参数
     * @return ChartVo 包含生成的图表信息的响应对象
     */
    @Override
    @Transactional
    public ChartVo genChartByAi(Long uid, MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest) {
        try{
            // 通过Redis限流，防止同一用户频繁调用
            redisLimiter.doRateLimit("genChartByAi_" + uid);

            // 校验请求参数
            String name = genChartByAiRequest.getName();
            String goal = genChartByAiRequest.getGoal();
            String chartType = genChartByAiRequest.getChartType();
            if(name == null || goal == null || chartType == null){
                throw new RuntimeException("参数不能为空");
            }

            // 检查文件大小
            long size = multipartFile.getSize();
            if(size > 1024 * 1024L){
                throw new RuntimeException("文件大小不能超过1M");
            }

            // 校验文件类型
            final List<String> validFileSuffixList = Arrays.asList("xlsx", "xls");
            String fileName = multipartFile.getOriginalFilename();
            String suffix = FileUtil.getSuffix(fileName);
            if(!validFileSuffixList.contains(suffix)){
                throw new RuntimeException("文件类型不支持");
            }

            // 处理用户目标信息
            String userGoal = null;
            if(StringUtils.isNotBlank(chartType)){
                userGoal = goal + "，请使用" + chartType;
            }

            // 组装用户需求和原始数据信息
            StringBuilder sb = new StringBuilder();
            sb.append("分析需求：").append(userGoal).append("\n");
            String s1 = sb.toString();
            sb = new StringBuilder();
            String data = ExcelUtils.excelToCSV(multipartFile, suffix);
            sb.append("原始数据：").append(data).append("\n");
            String s2 = sb.toString();
            // 调用AI服务进行分析
            String res = bdManager.doChat(s1, s2);
            log.info("AI 生成结果：{}", res);
            String[] result = res.split("```");
            if(result.length < 2){
                throw new RuntimeException("AI 生成错误");
            }

            // 解析AI返回的结果，并保存到数据库
            String genChart = result[1];
            String genResult = result[2];
            Chart chart = Chart.builder()
                    .name(name)
                    .goal(goal)
                    .chartData(data)
                    .chartType(chartType)
                    .genChart(genChart)
                    .genResult(genResult)
                    .uid(uid)
                    .status("succeed")
                    .build();
            boolean save = this.save(chart);
            if(!save){
                log.info("保存表单失败");
                throw new RuntimeException("保存表单失败");
            }

            // 构建并返回响应对象
            ChartVo chartVo = new ChartVo();
            BeanUtils.copyProperties(chart, chartVo);
            return chartVo;
        }catch (Exception e){
            log.error("AI生成图表失败", e);
            throw new RuntimeException("AI生成图表失败");
        }

    }

    @Override
    public ChartVo genChartByAiAsync(Long uid, MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest) {
        return null;
    }

    /**
     * 通过AI异步生成图表
     *
     * @param uid 用户ID，用于标识请求的用户
     * @param multipartFile 用户上传的文件，目前支持Excel格式
     * @param genChartByAiRequest 包含图表生成的详细请求参数
     * @return ChartVo 包含生成的图表的ID
     * @throws RuntimeException 当参数为空、文件大小超过1MB、文件类型不支持时，抛出异常
     */
    @Override
    @Retryable
    public ChartVo genChartByAiAsyncMq(Long uid, MultipartFile multipartFile, GenChartByAiRequest genChartByAiRequest) {
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
        try{
            // 对生成图表请求进行限流
            redisLimiter.doRateLimit("genChartByAi_" + uid);

            // 校验请求参数
            String name = genChartByAiRequest.getName();
            String goal = genChartByAiRequest.getGoal();
            String chartType = genChartByAiRequest.getChartType();
            if(name == null || goal == null || chartType == null){
                throw new RuntimeException("参数不能为空");
            }

            // 检查文件大小
            long size = multipartFile.getSize();
            if(size > 1024 * 1024L){
                throw new RuntimeException("文件大小不能超过1M");
            }

            // 校验文件类型
            final List<String> validFileSuffixList = Arrays.asList("xlsx", "xls");
            String fileName = multipartFile.getOriginalFilename();
            String suffix = FileUtil.getSuffix(fileName);
            if(!validFileSuffixList.contains(suffix)){
                throw new RuntimeException("文件类型不支持");
            }

            // 处理用户目标信息
            String userGoal = null;
            if(StringUtils.isNotBlank(chartType)){
                userGoal = goal + "，请使用" + chartType;
            }

            // 构建分析需求和原始数据信息
            StringBuilder sb = new StringBuilder();
            sb.append("分析需求：").append(userGoal).append("\n");
            String data = ExcelUtils.excelToCSV(multipartFile, suffix);
            sb.append("原始数据：").append(data).append("\n");

            // 创建图表对象并保存
            Chart chart = Chart.builder()
                    .name(name)
                    .goal(goal)
                    .chartData(data)
                    .chartType(chartType)
                    .uid(uid)
                    .status("wait")
                    .build();
            boolean save = this.save(chart);
            if(!save){
                log.info("保存表单失败");
                throw new RuntimeException("保存表单失败");
            }
            transactionManager.commit(transactionStatus);
            List<Chart> list = this.list();
            log.info("chart长度：{}", list.size());
            // 发送消息，触发异步处理
            biMessageProducer.sendMessage(String.valueOf(chart.getId()));
            log.info("发送消息成功");
            // 构建并返回响应对象
            ChartVo chartVo = new ChartVo();
            chartVo.setChartId(chart.getId());
            return chartVo;
        }catch (Exception e){
            log.error("AI 异步调用失败", e);
            transactionManager.rollback(transactionStatus);
            throw new RuntimeException("AI 异步调用失败");
        }

    }

    @Override
    public boolean deleteChart(Long uid, Long id) {
        return false;
    }

    @Override
    public boolean updateChart(Long uid, ChartUpdateRequest chartUpdateRequest) {
        return false;
    }

    @Override
    public Page<ChartVo> listChartByPage(ChartQueryRequest chartQueryRequest) {
        return null;
    }

    @Override
    public Page<ChartVo> listMyChartByPage(Long uid, ChartQueryRequest chartQueryRequest) {
        try{
            long current = chartQueryRequest.getCurrent();
            long size = chartQueryRequest.getPageSize();
            if (uid == null || size <= 0 || current <= 0 || size > 20) {
                throw new RuntimeException("参数错误");
            }
            Page<Chart> chartPage = this.page(new Page<>(current, size),
                    getQueryWrapper(uid, chartQueryRequest));
            List<ChartVo> chartVoList = chartPage.getRecords().stream().map(chart -> {
                ChartVo chartVo = new ChartVo();
                BeanUtils.copyProperties(chart, chartVo);
                return chartVo;
            }).collect(Collectors.toList());
            Page<ChartVo> chartVo = new Page<>();
            chartVo.setTotal(chartPage.getTotal());
            chartVo.setPages(chartPage.getPages());
            chartVo.setCurrent(chartPage.getCurrent());
            chartVo.setSize(chartPage.getSize());
            chartVo.setRecords(chartVoList);
            return chartVo;
        }catch (Exception e){
            log.error("获取我的图表失败", e);
            throw new RuntimeException("获取我的图表失败");
        }

    }

    private QueryWrapper<Chart> getQueryWrapper(Long uid, ChartQueryRequest chartQueryRequest) {
        QueryWrapper<Chart> queryWrapper = new QueryWrapper<>();
        if (chartQueryRequest == null) {
            return queryWrapper;
        }
        String chartType = chartQueryRequest.getChartType();
        String goal = chartQueryRequest.getGoal();
        String name = chartQueryRequest.getName();
        String sortField = chartQueryRequest.getSortField();
        String sortOrder = chartQueryRequest.getSortOrder();
        Long id = chartQueryRequest.getId();
        queryWrapper.eq(id != null && id > 0, "id", id);
        queryWrapper.like(ObjectUtils.isNotEmpty(name), "name", name);
        queryWrapper.eq(StringUtils.isNotEmpty(goal), "goal", goal);
        queryWrapper.eq(StringUtils.isNotEmpty(chartType), "chart_type", chartType);
        queryWrapper.eq(StringUtils.isNotEmpty(uid.toString()), "uid", uid);
        queryWrapper.eq("is_delete", false);
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }
}
